/*****************************************************************************
Copyright 2006 Kervin L. Pierre
    EMAIL: otlkcon@adevsoft.com

This file is part of Otlkcon.

Otlkcon is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

Otlkcon is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Lesser GNU General Public License for more details.

You should have received a copy of the Lesser GNU General Public License
along with Otlkcon; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*******************************************************************************/

#include "StdAfx.h"


#ifdef OTLKCON_XP

#include "O_IXPLogon.h"
#include "O_IXPProvider.h"

extern const IID IID_IXPLogon;

extern HWND  otlkcon_eventHwnd;

extern map< O_ENTRYID *, void *, otlkcon_entryid_less >      otlkcon_event_objects;
extern CRITICAL_SECTION    otlkcon_objects_cs;

O_IXPLogon::O_IXPLogon()
{
    InitializeCriticalSection(&cs);
    objectId = 0;
	lpMAPISup = NULL;
}

HRESULT O_IXPLogon::Create(O_IXPProvider *xpp, otlkcon_memory *m)
{
    HRESULT result = S_OK;

    memObj = m;
    cRef = 1;

    lpXPP = xpp;

    statusCode = STATUS_AVAILABLE;

    return result;
}

HRESULT O_IXPLogon::Destroy()
{
    HRESULT result = S_OK;

	if(NULL != lpMAPISup)
	{
		lpMAPISup->Release();
		lpMAPISup = NULL;
	} // if
    return result;
}

STDMETHODIMP O_IXPLogon::QueryInterface (REFIID riid, void **ppv)
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
        L"inside O_IXPLogon->QueryInterface().\n");

    *ppv = NULL;

    if( memcmp(&riid, &IID_IUnknown, sizeof(IID)) &&
        memcmp(&riid, &IID_IXPLogon, sizeof(IID)))
    { 
        result = ResultFromScode(E_NOINTERFACE);
        return result;
    }

    AddRef();
    *ppv = (LPVOID)this;

    return result;
}

ULONG STDMETHODCALLTYPE O_IXPLogon::AddRef (void)
{
    return ++cRef;
}

ULONG STDMETHODCALLTYPE O_IXPLogon::Release (void)
{
    if ( --cRef == 0 )
    {
        Destroy();
    }

    return cRef;
}

STDMETHODIMP O_IXPLogon::AddressTypes(
  ULONG *lpulFlags, ULONG *lpcAdrType, LPTSTR **lpppszAdrTypeArray,
  ULONG *lpcMAPIUID, LPMAPIUID **lpppUIDArray  )
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
        L"inside IXPLogon->AddressTypes\n");

    *lpcAdrType = 1;
    char **typeArray = (char **)memObj->malloc(sizeof(char **));
    *typeArray = memObj->_strdup( OTLKCON_ADDRESS_TYPE );
    *lpppszAdrTypeArray = typeArray;

    *lpcMAPIUID = 0;
    *lpppUIDArray = NULL;

    return result;
}

STDMETHODIMP O_IXPLogon::RegisterOptions(
  ULONG *lpulFlags,
  ULONG *lpcOptions,
  LPOPTIONDATA *lppOptions )
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
        L"inside IXPLogon->RegisterOptions\n");

    //TODO: This seems like an interesting function

    *lpulFlags = 0;
    *lpcOptions = 0;
    *lppOptions = NULL;

    return result;
}

STDMETHODIMP O_IXPLogon::TransportNotify(
  ULONG *lpulFlags,
  LPVOID *lppvData )
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
        L"inside IXPLogon->TransportNotify\n");

    //Check the flags
    if( *lpulFlags & NOTIFY_ABORT_DEFERRED )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,   OTLKCON_LOG_TARGET_ALL, 
            L"IXPProvider::TransportNotify() : NOTIFY_ABORT_DEFERRED set.\n" );
    }
    else if( *lpulFlags & NOTIFY_BEGIN_INBOUND )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,   OTLKCON_LOG_TARGET_ALL, 
            L"IXPProvider::TransportNotify() : NOTIFY_BEGIN_INBOUND set.\n" );

        statusCode |= STATUS_INBOUND_ENABLED;
    }
    else if( *lpulFlags & NOTIFY_BEGIN_INBOUND_FLUSH )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IXPProvider::TransportNotify() : NOTIFY_BEGIN_INBOUND_FLUSH set.\n" );

        statusCode |= STATUS_INBOUND_FLUSH;
    }
    else if( *lpulFlags & NOTIFY_BEGIN_OUTBOUND )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IXPProvider::TransportNotify() : NOTIFY_BEGIN_OUTBOUND set.\n" );

        statusCode |= STATUS_OUTBOUND_ENABLED;
    }
    else if( *lpulFlags & NOTIFY_BEGIN_OUTBOUND_FLUSH )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IXPProvider::TransportNotify() : NOTIFY_BEGIN_OUTBOUND_FLUSH set.\n" );
        
        statusCode |= STATUS_OUTBOUND_FLUSH;
    }
    else if( *lpulFlags & NOTIFY_CANCEL_MESSAGE )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IXPProvider::TransportNotify() : NOTIFY_CANCEL_MESSAGE set.\n" );
    }
    else if( *lpulFlags & NOTIFY_END_INBOUND )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IXPProvider::TransportNotify() : NOTIFY_END_INBOUND set.\n" );

        statusCode &= ~STATUS_INBOUND_ENABLED;
    }
    else if( *lpulFlags & NOTIFY_END_INBOUND_FLUSH )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IXPProvider::TransportNotify() : NOTIFY_END_INBOUND_FLUSH set.\n" );

        statusCode &= ~STATUS_INBOUND_FLUSH;
    }
    else if( *lpulFlags & NOTIFY_END_OUTBOUND )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IXPProvider::TransportNotify() : NOTIFY_END_OUTBOUND set.\n" );

        statusCode &= ~STATUS_OUTBOUND_ENABLED;
    }
    else if( *lpulFlags & NOTIFY_END_OUTBOUND_FLUSH )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IXPProvider::TransportNotify() : NOTIFY_END_OUTBOUND_FLUSH set.\n" );

        statusCode &= ~STATUS_OUTBOUND_FLUSH;
    }


    result = SetStatusCode();

    // Now do the work the flags requested here if needed

//transportnotify_end:
    return result;
}

STDMETHODIMP O_IXPLogon::SetStatusCode()
{
    HRESULT result = S_OK;
    SPropValue temprop = {0};

    temprop.ulPropTag = PR_STATUS_CODE;
    temprop.Value.l = statusCode;

    result = lpMAPISup->ModifyStatusRow( 1, &temprop, 0 );
    if( FAILED(result) )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"ERROR: result == %x", result );
        
        // TODO: cleanup, build error struct 
        result = E_FAIL;
    }

    return result;
}

STDMETHODIMP O_IXPLogon::Idle(ULONG ulFlags)
{
    HRESULT result = S_OK;

    //OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
    //    L"inside IXPLogon->Idle\n");

    return result;
}



STDMETHODIMP O_IXPLogon::TransportLogoff(ULONG ulFlags)
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
        L"inside IXPLogon->TransportLogoff\n");

	//Here we need to release all data allocated via MAPI

	if(NULL != lpMAPISup)
	{
		//Call this method to make all unreleased objects invalid
		//lpMAPISup->MakeInvalid()

		//that will cause to release transport provider
		lpMAPISup->Release();
		lpMAPISup = NULL;
	} // if

    return result;
}

STDMETHODIMP O_IXPLogon::SubmitMessage(
  ULONG ulFlags,
  LPMESSAGE lpMessage,
  ULONG *lpulMsgRef,
  ULONG *lpulReturnParm)
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
        L"inside IXPLogon->SubmitMessage\n");

    return result;
}

STDMETHODIMP O_IXPLogon::EndMessage(
  ULONG ulMsgRef,
  ULONG *lpulFlags )
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
        L"inside IXPLogon->EndMessage\n");

    return result;
}
 
STDMETHODIMP O_IXPLogon::Poll(  ULONG *lpulIncoming  )
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
        L"inside IXPLogon->Poll\n");

    // Poll the configured backends
    result = SyncAccounts();

    // TODO: Sync() should let us know if we have
    //       incoming messages or not.

    *lpulIncoming = NULL;

    return result;
}

STDMETHODIMP O_IXPLogon::StartMessage(
  ULONG ulFlags,
  LPMESSAGE lpMessage,
  ULONG *lpulMsgRef )
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
        L"inside IXPLogon->StartMessage\n");

    return result;
}

STDMETHODIMP O_IXPLogon::OpenStatusEntry(
  LPCIID lpInterface,
  ULONG ulFlags,
  ULONG *lpulObjType,
  LPMAPISTATUS *lppEntry )
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
        L"inside IXPLogon->OpenStatusEntry\n");

    return result;
}

STDMETHODIMP O_IXPLogon::ValidateState(
  ULONG ulUIParam,
  ULONG ulFlags )
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
        L"inside IXPLogon->ValidateState\n");

    return result;
}
 
STDMETHODIMP O_IXPLogon::FlushQueues(
  ULONG ulUIParam,
  ULONG cbTargetTransport,
  LPENTRYID lpTargetTransport,
  ULONG ulFlags )
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
        L"inside IXPLogon->FlushQueues\n");

    //Check the flags
    if( ulFlags & FLUSH_DOWNLOAD )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IXPLogon::FlushQueues() : FLUSH_DOWNLOAD set.\n" );

        statusCode |= STATUS_INBOUND_FLUSH;
    }
    else if( ulFlags & FLUSH_FORCE )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IXPLogon::FlushQueues() : FLUSH_FORCE set.\n" );
    }
    else if( ulFlags & FLUSH_NO_UI )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IXPLogon::FlushQueues() : FLUSH_NO_UI set.\n" );
    }
    else if( ulFlags & FLUSH_UPLOAD )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IXPLogon::FlushQueues() : FLUSH_UPLOAD set.\n" );

        statusCode |= STATUS_OUTBOUND_FLUSH;
    }

    result = SetStatusCode();

    return result;
}

HRESULT O_IXPLogon::SyncAccounts( )
{
    HRESULT result = S_OK;

    for( map<wstring,O_IXPLogonAccount*>::iterator i = accounts.begin();
        i != accounts.end(); ++i)
    {
        if( i->second->enabled || i->second->defaultAccount )
        {
            result = i->second->Sync();
            if( FAILED( result ) )
            {
                // FIXME: Reaction to failure should be a per account
                //        or per protocol setting.
                OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_ERROR,  OTLKCON_LOG_TARGET_ALL, 
                    L">>>>ERROR!!!! O_IXPLogon::SyncAccounts() : %S failed.\n", i->second->id.c_str() );

                OTLKCON_DEBUGBREAK;
            }
        }
    }

    return S_OK;
}

HRESULT O_IXPLogon::SyncAccount( wstring idStr )
{
    HRESULT result = S_OK;

    result = accounts[idStr]->Sync();

    return result;
}

O_IXPLogonAccount::O_IXPLogonAccount()
{
    ;
}

O_IXPLogonAccount::O_IXPLogonAccount( wstring idStr, int t, O_IXPLogon *xpp )
{
    HRESULT result = S_OK;

    id = idStr;
    type = t;
    lpXPLogon = xpp;
    
    user = pass = uri = name = L"";

    // Temporary entryID
    entryID             = (O_ENTRYID*)xpp->memObj->pMalloc( sizeof(O_ENTRYID) );
    result              = O_IProp::NewMAPIUID( &(entryID->instanceGuid) );
    entryID->typeGuid   = otlkcon_account_details_guid;
    // INFO: Use session type for accounts
    //entryID->typeID     = MAPI_SESSION;
    entryID->primarySupportedInterface = OTLKCON_IXPLOGONACCOUNT_CLASS;

    OTLKCON_ENTERCRITICALSECTION(&otlkcon_objects_cs,
                                "O_IXPLogonAccount::O_IXPLogonAccount");
    otlkcon_event_objects[entryID] = this;
    OTLKCON_LEAVECRITICALSECTION(&otlkcon_objects_cs,
                                "O_IXPLogonAccount::O_IXPLogonAccount");

    
}

O_IXPLogonAccountCalDAV::O_IXPLogonAccountCalDAV()
{
    caldavConn = new CaldavConnection();
}

O_IXPLogonAccountCalDAV::O_IXPLogonAccountCalDAV( wstring idStr, int t, O_IXPLogon *xpp )
                            :O_IXPLogonAccount(idStr,t,xpp)
{
    caldavConn = new CaldavConnection();
}

HRESULT O_IXPLogonAccountCalDAV::Logon()
{
    HRESULT result = S_OK;

    result = caldavConn->Logon( uri, user, pass );

    return result;
}

HRESULT O_IXPLogonAccountCalDAV::Init()
{
    HRESULT result = S_OK;

    result = caldavConn->Init( id );

    return result;
}

HRESULT O_IXPLogonAccountCalDAV::Sync()
{
    HRESULT result = S_OK;
    otlkcon_event_struct *event = NULL;
    errno_t errRes = 0;

    // TODO: If this function is called and this account doesn't
    //       feel like syncing, then ignore it and just return.

    // Before we sync, make sure we have at least
    // a single MSP message store.
    if( lpXPLogon->lpXPP->MSPMsgStores.size() < 1 )
    {
        result = lpXPLogon->lpXPP->RefreshStores();
    }

    if( lpXPLogon->lpXPP->MSPMsgStores.size() < 1 )
    {
        // This time we have to leave
        result = E_FAIL;
        goto sync_end;
    }

    // Get all Event names
    map<wstring,wstring> *namePairs = new map<wstring,wstring>;
    list<wstring> *names = NULL;
    list<otlkcon_calendar_component *> *comps = new list<otlkcon_calendar_component *>;

    // Get events from the server
    result = caldavConn->GetAllEventNames( namePairs );
    if( FAILED(result) )
    {
		OTLKCON_DEBUGBREAK
        goto sync_end;
    }

    // Serialize map
    size_t mapSize = id.length() + 1;
    for( map<wstring,wstring>::iterator i=namePairs->begin();
        i!= namePairs->end(); ++i)
    {
        mapSize += i->first.length()  + 1;
        mapSize += i->second.length() + 1;
    }
    
    size_t namePairSize = mapSize;
    mapSize *= sizeof(wchar_t);

    wchar_t *namePairsStr = (wchar_t *)lpXPLogon->memObj->pMalloc( 
                                        (ULONG)mapSize );
    wchar_t *namePairsStrTmp = namePairsStr;
    
    errRes = wcsncpy_s(namePairsStrTmp, namePairSize, id.c_str(), id.length() );
    namePairsStrTmp += id.length() + 1;
    namePairSize -= id.length()+1;
    for( map<wstring,wstring>::iterator i=namePairs->begin();
        i!= namePairs->end(); ++i)
    {
        errRes = wcsncpy_s(namePairsStrTmp, 
            namePairSize, i->first.c_str(), i->first.length() );
        namePairsStrTmp += i->first.length() + 1;
        namePairSize -= i->first.length()+1;

        errRes = wcsncpy_s(namePairsStrTmp, 
            namePairSize, i->second.c_str(), i->second.length() );
        namePairsStrTmp += i->second.length() + 1;
        namePairSize -= i->second.length()+1;
    }

    event 
        = (otlkcon_event_struct *)lpXPLogon->memObj->pMalloc( 
                    (ULONG)sizeof(otlkcon_event_struct)+mapSize );
    memcpy(&(event->senderEntryID), entryID, sizeof(O_ENTRYID));

    // FIXME: This is definitely a point of concern.  We can't just
    //        send to the first MSP message store we find.  Accounts
    //        should map to specific stores.
    memcpy(&(event->entryID), 
        lpXPLogon->lpXPP->MSPMsgStores[0]->entryID, sizeof(O_ENTRYID));

    event->cbData            = (ULONG)mapSize;
    memcpy(&(event->data), namePairsStr, mapSize);
    event->senderHWND = otlkcon_eventHwnd;
    lpXPLogon->memObj->pFree( namePairsStr);
  
    // Inform the message store provider of those event found on the remote server
    event->eventType = OTLKCON_EVENT_APPOINTMENT_NAME_REQ;
    result = otlkcon_event_sendmessage( otlkcon_eventHwnd, event->senderHWND, event );
    //lpXPLogon->memObj->pFree( event );
    
sync_end:
    return result;
}

// This function receives a list of resources names to resource names to download.
// It will request those from the server and return the result to the event source.
HRESULT O_IXPLogonAccountCalDAV::OnSyncAppointmentNameResult( otlkcon_event_struct *event )
{
    HRESULT result = S_OK;
    list<wstring> *names = NULL;
    otlkcon_calendar_component_array *comps = NULL;
    otlkcon_event_struct *ev = NULL;
    wchar_t *tmpNames;
    ULONG dataSize = 0;

    // FIXME: Deletes will be instantaneous or not at all, same with additions.
    //map<wstring,wstring> delNamePairs;

    tmpNames = (wchar_t *)(event->data);

    names = new list<wstring>();
    while( wcslen(tmpNames) )
    {
        names->push_back( tmpNames );
        tmpNames += wcslen(tmpNames)+1;
    }

    if( names->size() < 1 )
    {
        // Nothing to ask for
        result = S_OK;
        goto onsyncappointmentnameresult_end;
    }

    // Use the names returned to get the actual components.
    result = caldavConn->GetEventsByName( *names, &comps );
    if( result != S_OK || comps == NULL )
    {
        OTLKCON_DEBUGBREAK;
        goto onsyncappointmentnameresult_end;
    }

    dataSize = (ULONG)sizeof(otlkcon_calendar_component_array) 
                        + comps->size + id.length()*sizeof(wchar_t)+1;
    ev = (otlkcon_event_struct *)lpXPLogon->memObj->pMalloc( sizeof(otlkcon_event_struct) 
                    + dataSize );
    memcpy(&(ev->senderEntryID), entryID, sizeof(O_ENTRYID));
    memcpy(&(ev->entryID), &(event->senderEntryID), sizeof(O_ENTRYID));
    ev->cbData            =  dataSize;
    memcpy(&(ev->data), id.c_str(), id.length()*sizeof(wchar_t));
    // memcpy(&(ev->data)+id.length()*sizeof(wchar_t)+1, comps, 
    memcpy(&(ev->data)+id.length()+1, comps, 
        sizeof(otlkcon_calendar_component_array) + comps->size );
    ev->senderHWND = otlkcon_eventHwnd;

    ev->eventType = OTLKCON_EVENT_SYNC_APPOINTMENT_COMPS;
    result = otlkcon_event_sendmessage( otlkcon_eventHwnd, event->senderHWND, ev );

    // Delete marked appointmentments
    //ev->eventType = OTLKCON_EVENT_DEL_APPOINTMENTS;
    //result = otlkcon_event_sendmessage( otlkcon_eventHwnd, otlkcon_eventHwnd, ev );
    //result = lpXPLogon->lpXPP->lpMsgStore->DeleteAppointments( id, delNamePairs );

onsyncappointmentnameresult_end:
    return result;
}

HRESULT O_IXPLogonAccountCalDAV::OnUploadICal( otlkcon_event_struct *ev )
{
    HRESULT result = S_OK;
    icalcomponent *comp = NULL;
    wchar_t *tmpIdW, *tmpICalW;
    char *tmpICalA;
    errno_t errRes = 0;

    if( ev == NULL )
    {
        OTLKCON_DEBUGBREAK;
        return E_FAIL;
    }

    // First is the flag
    ULONG uFlag = (ULONG)&(ev->data[0]);

    // Now the data...
    tmpIdW = (wchar_t *)&(ev->data[4]);
    tmpICalW = (wchar_t *)(tmpIdW+wcslen(tmpIdW)+1);

    tmpICalA = (char *)lpXPLogon->memObj->pMalloc( (ULONG)wcslen(tmpICalW)+1 );
    _snprintf_s(tmpICalA, (ULONG)wcslen(tmpICalW)+1,
                            wcslen(tmpICalW), "%S", tmpICalW);

    comp = icalparser_parse_string( tmpICalA );
    lpXPLogon->memObj->pFree( tmpICalA );

    wchar_t* lpNewID = NULL;
	lpNewID = tmpIdW;
	wchar_t* lpNewEtag = NULL;
    ULONG ulNewETag = 0;

	result = caldavConn->PutNewComponent( comp, lpNewID, &lpNewEtag, &ulNewETag,
                                            (ULONG)uFlag );
    if( result != S_OK )
    {
		//TODO: report error to the user
		//OTLKCON_DEBUGBREAK;
        return E_FAIL;
    }
	else
	{
		//Send result message
		DWORD cbData 
            = (DWORD)(wcslen(lpNewID)+wcslen(lpNewEtag)+2)*sizeof(wchar_t);
		
		otlkcon_event_struct * pResEvent = (otlkcon_event_struct *)lpXPLogon->memObj->pMalloc(
			sizeof(otlkcon_event_struct) + cbData );
		pResEvent->eventType = OTLKCON_EVENT_UPLOAD_ICAL_RES;
		pResEvent->senderHWND = otlkcon_eventHwnd;
		pResEvent->cbData = cbData;
		memcpy(&(pResEvent->senderEntryID), entryID, sizeof(O_ENTRYID));
		memcpy(&(pResEvent->entryID), &ev->senderEntryID, sizeof(O_ENTRYID));
		errRes = wcscpy_s((wchar_t*)&pResEvent->data[0], 
                        cbData/sizeof(wchar_t), lpNewID);
		errRes = wcscpy_s((wchar_t*)(&pResEvent->data[0]
                                    + (wcslen(lpNewID)+1)*sizeof(wchar_t)), 
                        (cbData/sizeof(wchar_t))-(wcslen(lpNewID)+1),
                        lpNewEtag);
		
		result = otlkcon_event_sendmessage( otlkcon_eventHwnd, otlkcon_eventHwnd, pResEvent );

		free(lpNewEtag);
	} // else
    
    return result;
}

HRESULT O_IXPLogonAccountCalDAV::OnDelAppointments( otlkcon_event_struct *ev )
{
    HRESULT result = S_OK;
    wstring resName;

    if( ev == NULL || ev->cbData < 1 )
    {
        OTLKCON_DEBUGBREAK;
        return E_FAIL;
    }

    // TODO:  This should allow a list of resources
    resName = (wchar_t *)(ev->data);

    result = caldavConn->DeleteResource( resName );
    if( result != S_OK )
    {
        return result;
    }

    return result;
}

HRESULT O_IXPLogonAccountCalDAV::ProcessEvent( otlkcon_event_struct *ev )
{
    HRESULT result = S_OK;

    switch( ev->eventType )
    {
        case OTLKCON_EVENT_APPOINTMENT_NAME_RES:
            result = OnSyncAppointmentNameResult( ev );
            break;

        case OTLKCON_EVENT_RELOAD_CONFIG:
            //result = OnReloadConfig( ev );
            ;
            break;

        case OTLKCON_EVENT_UPLOAD_ICAL:
            result = OnUploadICal( ev );
            break;

        case OTLKCON_EVENT_DEL_APPOINTMENTS:
            result = OnDelAppointments( ev );
            break;

        default:
            OTLKCON_DEBUGBREAK;
            break;
    }

    return result;
}

O_IXPLogonAccountFile::O_IXPLogonAccountFile()
{
    fileConn = new FileConnection();
}

O_IXPLogonAccountFile::O_IXPLogonAccountFile( wstring idStr, int t, O_IXPLogon *xpp )
                            :O_IXPLogonAccount(idStr,t,xpp)
{
    fileConn = new FileConnection();
}

HRESULT O_IXPLogonAccountFile::Logon()
{
    HRESULT result = S_OK;

    result = fileConn->Logon( uri, user, pass );

    return result;
}

HRESULT O_IXPLogonAccountFile::Init()
{
    HRESULT result = S_OK;

    result = fileConn->Init( id );

    return result;
}

HRESULT O_IXPLogonAccountFile::Sync()
{
    HRESULT result = S_OK;
    otlkcon_event_struct *event = NULL;

    return result;
}

HRESULT O_IXPLogonAccountFile::OnSyncAppointmentNameResult( otlkcon_event_struct *event )
{
    HRESULT result = S_OK;

    return result;
}

HRESULT O_IXPLogonAccountFile::ProcessEvent( otlkcon_event_struct *event )
{
    HRESULT result = S_OK;

    return result;
}
#endif /* OTLKCON_XP */